



<!DOCTYPE html>
<html lang="zh-CN">
  <head><meta name="generator" content="Hexo 3.9.0">
    <title>风格指南 — Vue.js</title>
    <meta charset="utf-8">
    <meta name="description" content="Vue.js - The Progressive JavaScript Framework">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="alternate" hreflang="x-default" href="https://vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="zh" href="https://cn.vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="ja" href="https://jp.vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="ru" href="https://ru.vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="ko" href="https://kr.vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="pt-BR" href="https://br.vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="fr" href="https://fr.vuejs.org/v2/style-guide/index.html">
    <link rel="alternate" hreflang="es" href="https://es.vuejs.org/v2/style-guide/index.html">

    <meta property="og:type" content="article">
    <meta property="og:title" content="风格指南 — Vue.js">
    <meta property="og:description" content="Vue.js - The Progressive JavaScript Framework">
    <meta property="og:image" content="https://cn.vuejs.org/images/logo.png">

    <meta name="twitter:card" content="summary">
    <meta name="twitter:title" content="风格指南 — Vue.js">
    <meta name="twitter:description" content="Vue.js - The Progressive JavaScript Framework">
    <meta name="twitter:image" content="https://cn.vuejs.org/images/logo.png">

    <link rel="apple-touch-icon" sizes="57x57" href="/vue2/images/icons/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/vue2/images/icons/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/vue2/images/icons/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/vue2/images/icons/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/vue2/images/icons/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/vue2/images/icons/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/vue2/images/icons/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/vue2/images/icons/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/vue2/images/icons/apple-icon-180x180.png">
    <link rel="icon" type="image/png" sizes="192x192" href="/vue2/images/icons/android-icon-192x192.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/vue2/images/icons/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="96x96" href="/vue2/images/icons/favicon-96x96.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/vue2/images/icons/favicon-16x16.png">
    <meta name="msapplication-TileImage" content="/images/icons/ms-icon-144x144.png">
    <link rel="icon" href="/vue2/images/logo.svg">

    <meta name="msapplication-TileColor" content="#4fc08d">
    <meta name="theme-color" content="#4fc08d">

    <meta name="msapplication-config" content="browserconfig.xml">
    <link rel="manifest" href="/vue2/manifest.json">

    <!-- <link href="https://fonts.gstatic.com" rel="preconnect" crossorigin> -->
    <!-- <link href="https://maxcdn.bootstrapcdn.com" rel="preconnect" crossorigin> -->

    <!-- <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600|Roboto Mono&display=swap" rel="stylesheet"> -->
    <!-- <link href="https://fonts.googleapis.com/css?family=Dosis:500&text=Vue.js&display=swap" rel="stylesheet"> -->

    <link href="//code.bdstatic.com/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

    <!-- main page styles -->
    <link rel="stylesheet" href="/vue2/css/page.css">

    <!-- this needs to be loaded before guide's inline scripts -->
    <script src="/vue2/js/vue.js"></script>

    

    <script>
      Vue.config.productionTip = false
      window.PAGE_TYPE = "style-guide"
    </script>

    <!-- ga -->
    <script>
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-46852172-3', 'cn.vuejs.org');
      ga('send', 'pageview');
    </script>

    <!-- vimeo analytics -->
    <!-- <script type="text/javascript" defer="defer" src="https://extend.vimeocdn.com/ga/72160148.js"></script> -->
</head>
  <body class="docs">

    

    <div id="mobile-bar">
      <a class="menu-button"></a>
      <a class="logo" href="/"></a>
    </div>
    <div>
  <div id="v3-banner">
    <span class="hidden-sm">非官方文档，仅为个人学习使用，查看官方文档请移步</span><a href="https://cn.vuejs.org/" target="_blank">这里</a>。
  </div>

  <header id="header">
    <a id="logo" href="/vue2/">
      <img src="/vue2/images/logo.svg" alt="vue logo">
      <span>Vue.js</span>
    </a>
    <ul id="nav">
      <li>
  <form id="search-form">
    <input type="text" id="search-query-nav" class="search-query st-default-search-input" aria-label="搜索">
  </form>
</li>
<li class="nav-dropdown-container learn">
  <a class="nav-link current">学习</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><h4>文档</h4></li>
    <li>
      <ul>
        <li><a href="/vue2/v2/guide/" class="nav-link">教程</a></li>
        <li><a href="/vue2/v2/api/" class="nav-link">API</a></li>
        <li><a href="/vue2/v2/style-guide/" class="nav-link current">风格指南</a></li>
        <li><a href="/vue2/v2/examples/" class="nav-link">示例</a></li>
        <li><a href="/vue2/v2/cookbook/" class="nav-link">Cookbook</a></li>
      </ul>
    </li>
    <li><h4>视频教程</h4></li>
    <li>
      <ul>
        <li>
          <a href="https://www.vuemastery.com/courses/" class="nav-link" target="_blank" rel="sponsored noopener">
            Vue Mastery (英文)
          </a>
        </li>
        <li>
          <a href="https://vueschool.io/?friend=vuejs&utm_source=Vuejs.org&utm_medium=Link&utm_content=Navbar%20Dropdown" class="nav-link" target="_blank" rel="sponsored noopener">
            Vue School (英文)
          </a>
        </li>
        <!-- start: special logic for cn -->
        <li>
          <a href="https://learning.dcloud.io/" class="nav-link" target="_blank" rel="sponsored noopener">
            DCloud 视频教程
          </a>
        </li>
        <!-- end: special logic for cn -->
      </ul>
    </li>
  </ul>
</li>

<li class="nav-dropdown-container ecosystem">
  <a class="nav-link">生态系统</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><h4>帮助</h4></li>
    <li><ul>
      <li><a href="https://forum.vuejs.org/" class="nav-link" target="_blank" rel="noopener">论坛</a></li>
      <li><a href="https://chat.vuejs.org/" class="nav-link" target="_blank" rel="noopener">聊天室</a></li>
      <li><a href="https://events.vuejs.org/meetups/" class="nav-link" target="_blank" rel="noopener">聚会</a></li>
    </ul></li>
    <li><h4>工具</h4></li>
    <li>
      <ul>
        <li><a href="https://github.com/vuejs/vue-devtools" class="nav-link" target="_blank" rel="noopener">Devtools</a></li>
        <li><a href="https://cli.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue CLI</a></li>
        <li><a href="https://vue-loader.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue Loader</a></li>
      </ul>
    </li>
    <li><h4>核心插件</h4></li>
    <li><ul>
      <li><a href="https://router.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue Router</a></li>
      <li><a href="https://vuex.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vuex</a></li>
      <li><a href="https://ssr.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue 服务端渲染</a></li>
    </ul></li>
    <li><h4>信息</h4></li>
    <li><ul>
      <li><a href="https://news.vuejs.org" class="nav-link" target="_blank" rel="noopener">周刊</a></li>
      <li><a href="https://github.com/vuejs/vue/projects/6" class="nav-link" target="_blank" rel="noopener">Roadmap</a></li>
      <li><a href="https://events.vuejs.org/" class="nav-link" target="_blank" rel="noopener">活动</a></li>
      <li><a href="https://twitter.com/vuejs" class="nav-link" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://medium.com/the-vue-point" class="nav-link" target="_blank" rel="noopener">博客</a></li>
      <li><a href="https://vuejobs.com/?ref=vuejs" class="nav-link" target="_blank" rel="noopener">工作</a></li>
      <li><a href="https://dev.to/t/vue" class="nav-link" target="_blank" rel="noopener">DEV 社区</a></li>
    </ul></li>
  </ul>
</li>

<li>
  <a href="/vue2/v2/guide/team.html" class="nav-link team">团队</a>
</li>
<li class="nav-dropdown-container resources">
  <a href="#" class="nav-link">资源列表</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="/vue2/resources/partners.html" class="nav-link">合作伙伴</a></li>
    <li><a href="/vue2/resources/themes.html" class="nav-link">主题</a></li>
    <li><a href="https://github.com/vuejs/awesome-vue" class="nav-link" target="_blank" rel="noopener">Awesome Vue</a></li>
    <li><a href="https://awesomejs.dev/for/vue/" class="nav-link" target="_blank" rel="noopener">浏览和 Vue 相关的包</a></li>
  </ul>
</li>

<!-- <li>
  <a href="/vue2/partners" class="nav-link ">Partners</a>
</li> -->
<li class="nav-dropdown-container support-vue">
  <a href="/support-vuejs/" class="nav-link">支持 Vue</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="/support-vuejs/#One-time-Donations" class="nav-link">一次性赞助</a></li>
    <li><a href="/support-vuejs/#Recurring-Pledges" class="nav-link">周期性赞助</a></li>
    <!-- start: special logic for cn -->
    <li><a href="https://www.smallsticker.com/%E8%B4%B4%E7%BA%B8/vue.html" rel="noopener" class="nav-link">贴纸</a></li>
    <li><a href="https://osholic.com/?utm_source=vue&utm_medium=dropdown" rel="noopener" class="nav-link">周边</a></li>
    <!-- end: special logic for cn -->
    <li><a href="https://vue.threadless.com" target="_blank" rel="noopener" class="nav-link">T 恤商店</a></li>
  </ul>
</li>

<li class="nav-dropdown-container language">
  <a class="nav-link">多语言</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="https://vuejs.org/v2/style-guide/index.html" class="nav-link">English</a></li>
    <li><a href="https://jp.vuejs.org/v2/style-guide/index.html" class="nav-link">日本語</a></li>
    <li><a href="https://ru.vuejs.org/v2/style-guide/index.html" class="nav-link">Русский</a></li>
    <li><a href="https://kr.vuejs.org/v2/style-guide/index.html" class="nav-link">한국어</a></li>
    <li><a href="https://br.vuejs.org/v2/style-guide/index.html" class="nav-link">Português</a></li>
    <li><a href="https://fr.vuejs.org/v2/style-guide/index.html" class="nav-link">Français</a></li>
    <li><a href="https://vi.vuejs.org/v2/style-guide/index.html" class="nav-link">Tiếng Việt</a></li>
    <li><a href="https://es.vuejs.org/v2/style-guide/index.html" class="nav-link">Español</a></li>
    <li><a href="https://docs.vuejs.id/v2/style-guide/index.html" class="nav-link">Bahasa Indonesia</a></li>
  </ul>
</li>

<!-- start: special logic for cn -->
<li><a href="https://github.com/vuejs/cn.vuejs.org/" target="_blank" class="nav-link contribute">参与翻译</a></li>
<!-- end: special logic for cn -->

    </ul>
  </header>
</div>

    
      <div id="main" class="fix-sidebar">
        
  

<div class="sidebar">
  <div class="sidebar-inner">
    
    <div class="list">
      <div id="sidebar-sponsors-special">
  <div class="main-sponsor">
    <!-- start: special logic for cn -->
    <span>特别赞助商</span>
    <div>
    <a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank" rel="sponsored noopener" class="logo">
      <img id="s-dcloud" alt="dcloud">
      <script>
      (function(){
        var el = document.getElementById("s-dcloud");
        var adImg = null;
        var altImg = "/vue2/images/dcloud2.png";
        var img = "/vue2/images/dcloud1.png";
        el.src = adImg || (altImg && Math.random() >= 0.5 ? altImg : img);
      })()
      </script>
    </a>
    </div>
    <div>
    <a href="https://authing.cn/welcome?from=vuejs" target="_blank" rel="sponsored noopener" class="logo">
      <img id="s-authing" alt="authing">
      <script>
      (function(){
        var el = document.getElementById("s-authing");
        var adImg = null;
        var altImg = null;
        var img = "/vue2/images/authing.svg";
        el.src = adImg || (altImg && Math.random() >= 0.5 ? altImg : img);
      })()
      </script>
    </a>
    </div>
    <div>
    <a href="https://qingfuwu.cn?utm_campaign=TR_eSJH7nqW&utm_content=&utm_medium=Web&utm_source=CH_53OxwryD&utm_term=" target="_blank" rel="sponsored noopener" class="logo">
      <img id="s-qingfuwu" alt="qingfuwu">
      <script>
      (function(){
        var el = document.getElementById("s-qingfuwu");
        var adImg = null;
        var altImg = null;
        var img = "/vue2/images/qingfuwu.svg";
        el.src = adImg || (altImg && Math.random() >= 0.5 ? altImg : img);
      })()
      </script>
    </a>
    </div>
    <!-- end: special logic for cn -->
  </div>
</div>
<!--
<div id="sidebar-sponsors-platinum-left">
  <div class="main-sponsor">
    <span>白金赞助商</span>
    <div>
    <a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/vueschool.png" alt="VueSchool">
    </a>
    <a href="https://vehikl.com/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/vehikl.png" alt="Vehikl">
    </a>
    <a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/retool.png" alt="Retool">
    </a>
    <a href="https://passionatepeople.io/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/passionate_people.png" alt="Passionate People">
    </a>
    <a href="https://www.storyblok.com" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/storyblok.png" alt="Storyblok">
    </a>
    <a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/ionic.png" alt="Ionic">
    </a>
    <a href="https://nuxtjs.org/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/nuxt.png" alt="Nuxt">
    </a>
    </div>
  </div>
  <a class="become-backer" href="/vue2/support-vuejs">
    成为赞助者
  </a>
</div>

-->

      
        <h2>
          
          风格指南
          
        </h2>
        <ul class="menu-root">
  
</ul>

      
    </div>
  </div>
</div>
<!--

<div id="sidebar-sponsors-platinum-right">
  <div class="main-sponsor">
    <span>白金赞助商</span>
    <div>
    <a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/vueschool.png" alt="VueSchool">
    </a>
    <a href="https://vehikl.com/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/vehikl.png" alt="Vehikl">
    </a>
    <a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/retool.png" alt="Retool">
    </a>
    <a href="https://passionatepeople.io/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/passionate_people.png" alt="Passionate People">
    </a>
    <a href="https://www.storyblok.com" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/storyblok.png" alt="Storyblok">
    </a>
    <a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/ionic.png" alt="Ionic">
    </a>
    <a href="https://nuxtjs.org/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/vue2/images/nuxt.png" alt="Nuxt">
    </a>
    </div>
  </div>
  <a class="become-backer" href="/vue2/support-vuejs">
    成为赞助者
  </a>
</div>


-->


<div class="content style-guide with-sidebar ">
  <p class="tip warning v3-warning">
    您在浏览的是 v2.x 及更早版本的文档。v3.x 的文档<a href="https://wangyubina.github.io/vue3/">在这里</a>。
  </p>

  
    
      
<div id="ad">
  <!-- start: special logic for cn -->
  <div class="wwads-cn wwads-vertical" data-id="53" style="max-width: 200px"></div>
  <script type="text/javascript" src="https://cdn.wwads.cn/js/makemoney.js" async></script>
  <!-- end: special logic for cn -->
  <!-- <script
    async
    type="text/javascript"
    src="//cdn.carbonads.com/carbon.js?serve=CEBDT27Y&placement=vuejsorg"
    id="_carbonads_js"
  ></script> -->
</div>


    
  
  
    <h1>风格指南</h1>
  

  <!-- start: special logic for cn -->
  <!-- start: special logic for cn -->
<!-- <div class="ad-pagetop">
  <a href="http://www.vueshop.com.cn/index.php?http_referer=vuejs" target="_blank" rel="noopener noreferrer">
    <span class="name">VUEshop</span>
    <span class="description">中国免费商城系统 - 搜豹商城系统 - 免费50小时 Vue 视频教程</span>
    <span class="action">立即查看 &gt;</span>
  </a>
</div> -->
<!-- end: special logic for cn -->

  <!-- end: special logic for cn -->

  
    <p>这里是官方的 Vue 特有代码的风格指南。如果在工程中使用 Vue，为了回避错误、小纠结和反模式，该指南是份不错的参考。不过我们也不确信风格指南的所有内容对于所有的团队或工程都是理想的。所以根据过去的经验、周围的技术栈、个人价值观做出有意义的偏差是可取的。</p>
<p>对于其绝大部分，我们也总体上避免就 JavaScript 或 HTML 的本身提出建议。我们不介意你是否使用分号或结尾的逗号。我们不介意你在 HTML attribute 中使用单引号还是双引号。不过当我们发现在 Vue 的情景下有帮助的特定模式时，也会存在例外。</p>
<blockquote>
<p><strong>不久之后，我们还会提供操作层面的技巧。</strong>有的时候你只需要遵守规则，而我们会尽可能向你展示如何使用 ESLint 及其它自动化程序把操作层面弄得更简单。</p>
</blockquote>
<p>最终，我们把所有的规则归为了四个大类：</p>
<h2 id="规则归类"><a href="#规则归类" class="headerlink" title="规则归类"></a>规则归类</h2><h3 id="优先级-A：必要的"><a href="#优先级-A：必要的" class="headerlink" title="优先级 A：必要的"></a>优先级 A：必要的</h3><p>这些规则会帮你规避错误，所以学习并接受它们带来的全部代价吧。这里面可能存在例外，但应该非常少，且只有你同时精通 JavaScript 和 Vue 才可以这样做。</p>
<h3 id="优先级-B：强烈推荐"><a href="#优先级-B：强烈推荐" class="headerlink" title="优先级 B：强烈推荐"></a>优先级 B：强烈推荐</h3><p>这些规则能够在绝大多数工程中改善可读性和开发体验。即使你违反了，代码还是能照常运行，但例外应该尽可能少且有合理的理由。</p>
<h3 id="优先级-C：推荐"><a href="#优先级-C：推荐" class="headerlink" title="优先级 C：推荐"></a>优先级 C：推荐</h3><p>当存在多个同样好的选项，选任意一个都可以确保一致性。在这些规则里，我们描述了每个选项并建议一个默认的选择。也就是说只要保持一致且理由充分，你可以随意在你的代码库中做出不同的选择。请务必给出一个好的理由！通过接受社区的标准，你将会：</p>
<ol>
<li>训练你的大脑，以便更容易的处理你在社区遇到的代码；</li>
<li>不做修改就可以直接复制粘贴社区的代码示例；</li>
<li>能够经常招聘到和你编码习惯相同的新人，至少跟 Vue 相关的东西是这样的。</li>
</ol>
<h3 id="优先级-D：谨慎使用"><a href="#优先级-D：谨慎使用" class="headerlink" title="优先级 D：谨慎使用"></a>优先级 D：谨慎使用</h3><p>有些 Vue 特性的存在是为了照顾极端情况或帮助老代码的平稳迁移。当被过度使用时，这些特性会让你的代码难于维护甚至变成 bug 的来源。这些规则是为了给有潜在风险的特性敲个警钟，并说明它们什么时候不应该使用以及为什么。</p>
<h2 id="优先级-A-的规则：必要的-规避错误"><a href="#优先级-A-的规则：必要的-规避错误" class="headerlink" title="优先级 A 的规则：必要的 (规避错误)"></a>优先级 A 的规则：必要的 (规避错误)</h2><h3 id="组件名为多个单词必要"><a href="#组件名为多个单词必要" class="headerlink" title="组件名为多个单词必要"></a>组件名为多个单词<sup data-p="a">必要</sup></h3><p><strong>组件名应该始终是多个单词的，根组件 <code>App</code> 以及 <code>&lt;transition&gt;</code>、<code>&lt;component&gt;</code> 之类的 Vue 内置组件除外。</strong></p>
<p>这样做可以避免跟现有的以及未来的 HTML 元素<a href="https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name" target="_blank" rel="noopener">相冲突</a>，因为所有的 HTML 元素名称都是单个单词的。</p>
<div class="style-example example-bad">
<h4 id="反例"><a href="#反例" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'todo'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Todo'</span>,
  <span class="hljs-comment">// ...</span>
&#125;</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子"><a href="#好例子" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'todo-item'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">name</span>: <span class="hljs-string">'TodoItem'</span>,
  <span class="hljs-comment">// ...</span>
&#125;</code></pre>
</div>
<h3 id="组件数据必要"><a href="#组件数据必要" class="headerlink" title="组件数据必要"></a>组件数据<sup data-p="a">必要</sup></h3><p><strong>组件的 <code>data</code> 必须是一个函数。</strong></p>
<p>当在组件中使用 <code>data</code> property 的时候 (除了 <code>new Vue</code> 外的任何地方)，它的值必须是返回一个对象的函数。</p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>当 <code>data</code> 的值是一个对象时，它会在这个组件的所有实例之间共享。想象一下，假如一个 <code>TodoList</code> 组件的数据是这样的：</p>
<pre><code class="hljs js">data: &#123;
  <span class="hljs-attr">listTitle</span>: <span class="hljs-string">''</span>,
  <span class="hljs-attr">todos</span>: []
&#125;</code></pre>
<p>我们可能希望重用这个组件，允许用户维护多个列表 (比如分为购物、心愿单、日常事务等)。这时就会产生问题。因为每个组件的实例都引用了相同的数据对象，更改其中一个列表的标题就会改变其它每一个列表的标题。增删改一个待办事项的时候也是如此。</p>
<p>取而代之的是，我们希望每个组件实例都管理其自己的数据。为了做到这一点，每个实例必须生成一个独立的数据对象。在 JavaScript 中，在一个函数中返回这个对象就可以了：</p>
<pre><code class="hljs js">data: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
  <span class="hljs-keyword">return</span> &#123;
    <span class="hljs-attr">listTitle</span>: <span class="hljs-string">''</span>,
    <span class="hljs-attr">todos</span>: []
  &#125;
&#125;</code></pre>
</details>
<div class="style-example example-bad">
<h4 id="反例-1"><a href="#反例-1" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'some-comp'</span>, &#123;
  <span class="hljs-attr">data</span>: &#123;
    <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span>
  &#125;
&#125;)</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">data</span>: &#123;
    <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span>
  &#125;
&#125;</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-1"><a href="#好例子-1" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'some-comp'</span>, &#123;
  <span class="hljs-attr">data</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">return</span> &#123;
      <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span>
    &#125;
  &#125;
&#125;)</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// In a .vue file</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  data () &#123;
    <span class="hljs-keyword">return</span> &#123;
      <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span>
    &#125;
  &#125;
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// 在一个 Vue 的根实例上直接使用对象是可以的，</span>
<span class="hljs-comment">// 因为只存在一个这样的实例。</span>
<span class="hljs-keyword">new</span> Vue(&#123;
  <span class="hljs-attr">data</span>: &#123;
    <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span>
  &#125;
&#125;)</code></pre>
</div>
<h3 id="Prop-定义必要"><a href="#Prop-定义必要" class="headerlink" title="Prop 定义必要"></a>Prop 定义<sup data-p="a">必要</sup></h3><p><strong>Prop 定义应该尽量详细。</strong></p>
<p>在你提交的代码中，prop 的定义应该尽量详细，至少需要指定其类型。</p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>细致的 <a href="../guide/components-props.html#Prop-验证">prop 定义</a>有两个好处：</p>
<ul>
<li>它们写明了组件的 API，所以很容易看懂组件的用法；</li>
<li>在开发环境下，如果向一个组件提供格式不正确的 prop，Vue 将会告警，以帮助你捕获潜在的错误来源。</li>
</ul>
</details>
<div class="style-example example-bad">
<h4 id="反例-2"><a href="#反例-2" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js"><span class="hljs-comment">// 这样做只有开发原型系统时可以接受</span>
<span class="hljs-attr">props</span>: [<span class="hljs-string">'status'</span>]</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-2"><a href="#好例子-2" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">props: &#123;
  <span class="hljs-attr">status</span>: <span class="hljs-built_in">String</span>
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// 更好的做法！</span>
<span class="hljs-attr">props</span>: &#123;
  <span class="hljs-attr">status</span>: &#123;
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">validator</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value</span>) </span>&#123;
      <span class="hljs-keyword">return</span> [
        <span class="hljs-string">'syncing'</span>,
        <span class="hljs-string">'synced'</span>,
        <span class="hljs-string">'version-conflict'</span>,
        <span class="hljs-string">'error'</span>
      ].indexOf(value) !== <span class="hljs-number">-1</span>
    &#125;
  &#125;
&#125;</code></pre>
</div>
<h3 id="为-v-for-设置键值必要"><a href="#为-v-for-设置键值必要" class="headerlink" title="为 v-for 设置键值必要"></a>为 <code>v-for</code> 设置键值<sup data-p="a">必要</sup></h3><p><strong>总是用 <code>key</code> 配合 <code>v-for</code>。</strong></p>
<p>在组件上<em>总是</em>必须用 <code>key</code> 配合 <code>v-for</code>，以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为，比如动画中的<a href="https://bost.ocks.org/mike/constancy/" target="_blank" rel="noopener">对象固化 (object constancy)</a>，也是一种好的做法。</p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>假设你有一个待办事项列表：</p>
<pre><code class="hljs js">data: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
  <span class="hljs-keyword">return</span> &#123;
    <span class="hljs-attr">todos</span>: [
      &#123;
        <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">text</span>: <span class="hljs-string">'学习使用 v-for'</span>
      &#125;,
      &#123;
        <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">text</span>: <span class="hljs-string">'学习使用 key'</span>
      &#125;
    ]
  &#125;
&#125;</code></pre>
<p>然后你把它们按照字母顺序排序。在更新 DOM 的时候，Vue 将会优化渲染把可能的 DOM 变更降到最低。即可能删掉第一个待办事项元素，然后把它重新加回到列表的最末尾。</p>
<p>这里的问题在于，不要删除仍然会留在 DOM 中的元素。比如你想使用 <code>&lt;transition-group&gt;</code> 给列表加过渡动画，或想在被渲染元素是 <code>&lt;input&gt;</code> 时保持聚焦。在这些情况下，为每一个项目添加一个唯一的键值 (比如 <code>:key=&quot;todo.id&quot;</code>) 将会让 Vue 知道如何使行为更容易预测。</p>
<p>根据我们的经验，最好<em>始终</em>添加一个唯一的键值，以便你和你的团队永远不必担心这些极端情况。也在少数对性能有严格要求的情况下，为了避免对象固化，你可以刻意做一些非常规的处理。</p>
</details>
<div class="style-example example-bad">
<h4 id="反例-3"><a href="#反例-3" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"todo in todos"</span>&gt;</span>
    &#123;&#123; todo.text &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-3"><a href="#好例子-3" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"todo in todos"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"todo.id"</span>
  &gt;</span>
    &#123;&#123; todo.text &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
</div>
<h3 id="避免-v-if-和-v-for-用在一起必要"><a href="#避免-v-if-和-v-for-用在一起必要" class="headerlink" title="避免 v-if 和 v-for 用在一起必要"></a>避免 <code>v-if</code> 和 <code>v-for</code> 用在一起<sup data-p="a">必要</sup></h3><p><strong>永远不要把 <code>v-if</code> 和 <code>v-for</code> 同时用在同一个元素上。</strong></p>
<p>一般我们在两种常见的情况下会倾向于这样做：</p>
<ul>
<li><p>为了过滤一个列表中的项目 (比如 <code>v-for=&quot;user in users&quot; v-if=&quot;user.isActive&quot;</code>)。在这种情形下，请将 <code>users</code> 替换为一个计算属性 (比如 <code>activeUsers</code>)，让其返回过滤后的列表。</p>
</li>
<li><p>为了避免渲染本应该被隐藏的列表 (比如 <code>v-for=&quot;user in users&quot; v-if=&quot;shouldShowUsers&quot;</code>)。这种情形下，请将 <code>v-if</code> 移动至容器元素上 (比如 <code>ul</code>、<code>ol</code>)。</p>
</li>
</ul>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>当 Vue 处理指令时，<code>v-for</code> 比 <code>v-if</code> 具有更高的优先级，所以这个模板：</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span>
    <span class="hljs-attr">v-if</span>=<span class="hljs-string">"user.isActive"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<p>将会经过如下运算：</p>
<pre><code class="hljs js"><span class="hljs-keyword">this</span>.users.map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">user</span>) </span>&#123;
  <span class="hljs-keyword">if</span> (user.isActive) &#123;
    <span class="hljs-keyword">return</span> user.name
  &#125;
&#125;)</code></pre>
<p>因此哪怕我们只渲染出一小部分用户的元素，也得在每次重渲染的时候遍历整个列表，不论活跃用户是否发生了变化。</p>
<p>通过将其更换为在如下的一个计算属性上遍历：</p>
<pre><code class="hljs js">computed: &#123;
  <span class="hljs-attr">activeUsers</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.users.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">user</span>) </span>&#123;
      <span class="hljs-keyword">return</span> user.isActive
    &#125;)
  &#125;
&#125;</code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in activeUsers"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<p>我们将会获得如下好处：</p>
<ul>
<li>过滤后的列表<em>只</em>会在 <code>users</code> 数组发生相关变化时才被重新运算，过滤更高效。</li>
<li>使用 <code>v-for=&quot;user in activeUsers&quot;</code> 之后，我们在渲染的时候<em>只</em>遍历活跃用户，渲染更高效。</li>
<li>解耦渲染层的逻辑，可维护性 (对逻辑的更改和扩展) 更强。</li>
</ul>
<p>为了获得同样的好处，我们也可以把：</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span>
    <span class="hljs-attr">v-if</span>=<span class="hljs-string">"shouldShowUsers"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<p>更新为：</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"shouldShowUsers"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<p>通过将 <code>v-if</code> 移动到容器元素，我们不会再对列表中的<em>每个</em>用户检查 <code>shouldShowUsers</code>。取而代之的是，我们只检查它一次，且不会在 <code>shouldShowUsers</code> 为否的时候运算 <code>v-for</code>。</p>
</details>
<div class="style-example example-bad">
<h4 id="反例-4"><a href="#反例-4" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span>
    <span class="hljs-attr">v-if</span>=<span class="hljs-string">"user.isActive"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span>
    <span class="hljs-attr">v-if</span>=<span class="hljs-string">"shouldShowUsers"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-4"><a href="#好例子-4" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in activeUsers"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"shouldShowUsers"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>
  &gt;</span>
    &#123;&#123; user.name &#125;&#125;
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
</div>
<h3 id="为组件样式设置作用域必要"><a href="#为组件样式设置作用域必要" class="headerlink" title="为组件样式设置作用域必要"></a>为组件样式设置作用域<sup data-p="a">必要</sup></h3><p><strong>对于应用来说，顶级 <code>App</code> 组件和布局组件中的样式可以是全局的，但是其它所有组件都应该是有作用域的。</strong></p>
<p>这条规则只和<a href="../guide/single-file-components.html">单文件组件</a>有关。你<em>不一定</em>要使用 <a href="https://vue-loader.vuejs.org/zh-cn/features/scoped-css.html" target="_blank" rel="noopener"><code>scoped</code> attribute</a>。设置作用域也可以通过 <a href="https://vue-loader.vuejs.org/zh-cn/features/css-modules.html" target="_blank" rel="noopener">CSS Modules</a>，那是一个基于 class 的类似 <a href="http://getbem.com/" target="_blank" rel="noopener">BEM</a> 的策略，当然你也可以使用其它的库或约定。</p>
<p><strong>不管怎样，对于组件库，我们应该更倾向于选用基于 class 的策略而不是 <code>scoped</code> attribute。</strong></p>
<p>这让覆写内部样式更容易：使用了常人可理解的 class 名称且没有太高的选择器优先级，而且不太会导致冲突。</p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>如果你和其他开发者一起开发一个大型工程，或有时引入三方 HTML/CSS (比如来自 Auth0)，设置一致的作用域会确保你的样式只会运用在它们想要作用的组件上。</p>
<p>不止要使用 <code>scoped</code> attribute，使用唯一的 class 名可以帮你确保那些三方库的 CSS 不会运用在你自己的 HTML 上。比如许多工程都使用了 <code>button</code>、<code>btn</code> 或 <code>icon</code> class 名，所以即便你不使用类似 BEM 的策略，添加一个 app 专属或组件专属的前缀 (比如 <code>ButtonClose-icon</code>) 也可以提供很多保护。</p>
</details>
<div class="style-example example-bad">
<h4 id="反例-5"><a href="#反例-5" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-close"</span>&gt;</span>X<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.btn-close</span> &#123;
  <span class="hljs-attribute">background-color</span>: red;
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-5"><a href="#好例子-5" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button button-close"</span>&gt;</span>X<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 使用 `scoped` attribute --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.button</span> &#123;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2px</span>;
&#125;

<span class="hljs-selector-class">.button-close</span> &#123;
  <span class="hljs-attribute">background-color</span>: red;
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"[$style.button, $style.buttonClose]"</span>&gt;</span>X<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 使用 CSS Modules --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">module</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.button</span> &#123;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2px</span>;
&#125;

<span class="hljs-selector-class">.buttonClose</span> &#123;
  <span class="hljs-attribute">background-color</span>: red;
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"c-Button c-Button--close"</span>&gt;</span>X<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 使用 BEM 约定 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.c-Button</span> &#123;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2px</span>;
&#125;

<span class="hljs-selector-class">.c-Button--close</span> &#123;
  <span class="hljs-attribute">background-color</span>: red;
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
</div>
<h3 id="私有-property-名必要"><a href="#私有-property-名必要" class="headerlink" title="私有 property 名必要"></a>私有 property 名<sup data-p="a">必要</sup></h3><p><strong>使用模块作用域保持不允许外部访问的函数的私有性。如果无法做到这一点，就始终为插件、混入等不考虑作为对外公共 API 的自定义私有 property 使用 <code>$_</code> 前缀。并附带一个命名空间以回避和其它作者的冲突 (比如 <code>$_yourPluginName_</code>)。</strong></p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>Vue 使用 <code>_</code> 前缀来定义其自身的私有 property，所以使用相同的前缀 (比如 <code>_update</code>) 有覆写实例 property 的风险。即便你检查确认 Vue 当前版本没有用到这个 property 名，也不能保证和将来的版本没有冲突。</p>
<p>对于 <code>$</code> 前缀来说，其在 Vue 生态系统中的目的是暴露给用户的一个特殊的实例 property，所以把它用于<em>私有</em> property 并不合适。</p>
<p>不过，我们推荐把这两个前缀结合为 <code>$_</code>，作为一个用户定义的私有 property 的约定，以确保不会和 Vue 自身相冲突。</p>
</details>
<div class="style-example example-bad">
<h4 id="反例-6"><a href="#反例-6" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js"><span class="hljs-keyword">var</span> myGreatMixin = &#123;
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">methods</span>: &#123;
    <span class="hljs-attr">update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
      <span class="hljs-comment">// ...</span>
    &#125;
  &#125;
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> myGreatMixin = &#123;
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">methods</span>: &#123;
    <span class="hljs-attr">_update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
      <span class="hljs-comment">// ...</span>
    &#125;
  &#125;
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> myGreatMixin = &#123;
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">methods</span>: &#123;
    <span class="hljs-attr">$update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
      <span class="hljs-comment">// ...</span>
    &#125;
  &#125;
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> myGreatMixin = &#123;
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">methods</span>: &#123;
    <span class="hljs-attr">$_update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
      <span class="hljs-comment">// ...</span>
    &#125;
  &#125;
&#125;</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-6"><a href="#好例子-6" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js"><span class="hljs-keyword">var</span> myGreatMixin = &#123;
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">methods</span>: &#123;
    <span class="hljs-attr">$_myGreatMixin_update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
      <span class="hljs-comment">// ...</span>
    &#125;
  &#125;
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// 甚至更好！</span>
<span class="hljs-keyword">var</span> myGreatMixin = &#123;
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">methods</span>: &#123;
    publicMethod() &#123;
      <span class="hljs-comment">// ...</span>
      myPrivateFunction()
    &#125;
  &#125;
&#125;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myPrivateFunction</span>(<span class="hljs-params"></span>) </span>&#123;
  <span class="hljs-comment">// ...</span>
&#125;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> myGreatMixin</code></pre>
</div>
<h2 id="优先级-B-的规则：强烈推荐-增强可读性"><a href="#优先级-B-的规则：强烈推荐-增强可读性" class="headerlink" title="优先级 B 的规则：强烈推荐 (增强可读性)"></a>优先级 B 的规则：强烈推荐 (增强可读性)</h2><h3 id="组件文件强烈推荐"><a href="#组件文件强烈推荐" class="headerlink" title="组件文件强烈推荐"></a>组件文件<sup data-p="b">强烈推荐</sup></h3><p><strong>只要有能够拼接文件的构建系统，就把每个组件单独分成文件。</strong></p>
<p>当你需要编辑一个组件或查阅一个组件的用法时，可以更快速的找到它。</p>
<div class="style-example example-bad">
<h4 id="反例-7"><a href="#反例-7" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'TodoList'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)

Vue.component(<span class="hljs-string">'TodoItem'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-7"><a href="#好例子-7" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- TodoList.js
|- TodoItem.js</code></pre>
<pre><code class="hljs undefined">components/
|- TodoList.vue
|- TodoItem.vue</code></pre>
</div>
<h3 id="单文件组件文件的大小写强烈推荐"><a href="#单文件组件文件的大小写强烈推荐" class="headerlink" title="单文件组件文件的大小写强烈推荐"></a>单文件组件文件的大小写<sup data-p="b">强烈推荐</sup></h3><p><strong><a href="../guide/single-file-components.html">单文件组件</a>的文件名应该要么始终是单词大写开头 (PascalCase)，要么始终是横线连接 (kebab-case)。</strong></p>
<p>单词大写开头对于代码编辑器的自动补全最为友好，因为这使得我们在 JS(X) 和模板中引用组件的方式尽可能的一致。然而，混用文件命名方式有的时候会导致大小写不敏感的文件系统的问题，这也是横线连接命名同样完全可取的原因。</p>
<div class="style-example example-bad">
<h4 id="反例-8"><a href="#反例-8" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs undefined">components/
|- mycomponent.vue</code></pre>
<pre><code class="hljs undefined">components/
|- myComponent.vue</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-8"><a href="#好例子-8" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- MyComponent.vue</code></pre>
<pre><code class="hljs undefined">components/
|- my-component.vue</code></pre>
</div>
<h3 id="基础组件名强烈推荐"><a href="#基础组件名强烈推荐" class="headerlink" title="基础组件名强烈推荐"></a>基础组件名<sup data-p="b">强烈推荐</sup></h3><p><strong>应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头，比如 <code>Base</code>、<code>App</code> 或 <code>V</code>。</strong></p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>这些组件为你的应用奠定了一致的基础样式和行为。它们可能<strong>只</strong>包括：</p>
<ul>
<li>HTML 元素</li>
<li>其它基础组件</li>
<li>第三方 UI 组件库</li>
</ul>
<p>但是它们<strong>绝不会</strong>包括全局状态 (比如来自 Vuex store)。</p>
<p>它们的名字通常包含所包裹元素的名字 (比如 <code>BaseButton</code>、<code>BaseTable</code>)，除非没有现成的对应功能的元素 (比如 <code>BaseIcon</code>)。如果你为特定的上下文构建类似的组件，那它们几乎总会消费这些组件 (比如 <code>BaseButton</code> 可能会用在 <code>ButtonSubmit</code> 上)。</p>
<p>这样做的几个好处：</p>
<ul>
<li><p>当你在编辑器中以字母顺序排序时，你的应用的基础组件会全部列在一起，这样更容易识别。</p>
</li>
<li><p>因为组件名应该始终是多个单词，所以这样做可以避免你在包裹简单组件时随意选择前缀 (比如 <code>MyButton</code>、<code>VueButton</code>)。</p>
</li>
<li><p>因为这些组件会被频繁使用，所以你可能想把它们放到全局而不是在各处分别导入它们。使用相同的前缀可以让 webpack 这样工作：</p>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> requireComponent = <span class="hljs-built_in">require</span>.context(<span class="hljs-string">"./src"</span>, <span class="hljs-literal">true</span>, /Base[A-Z]\w+\.(vue|js)$/)
requireComponent.keys().forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">fileName</span>) </span>&#123;
  <span class="hljs-keyword">var</span> baseComponentConfig = requireComponent(fileName)
  baseComponentConfig = baseComponentConfig.default || baseComponentConfig
  <span class="hljs-keyword">var</span> baseComponentName = baseComponentConfig.name || (
    fileName
      .replace(<span class="hljs-regexp">/^.+\//</span>, <span class="hljs-string">''</span>)
      .replace(<span class="hljs-regexp">/\.\w+$/</span>, <span class="hljs-string">''</span>)
  )
  Vue.component(baseComponentName, baseComponentConfig)
&#125;)</code></pre>
</li>
</ul>
</details>
<div class="style-example example-bad">
<h4 id="反例-9"><a href="#反例-9" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs undefined">components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-9"><a href="#好例子-9" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue</code></pre>
<pre><code class="hljs undefined">components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue</code></pre>
<pre><code class="hljs undefined">components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue</code></pre>
</div>
<h3 id="单例组件名强烈推荐"><a href="#单例组件名强烈推荐" class="headerlink" title="单例组件名强烈推荐"></a>单例组件名<sup data-p="b">强烈推荐</sup></h3><p><strong>只应该拥有单个活跃实例的组件应该以 <code>The</code> 前缀命名，以示其唯一性。</strong></p>
<p>这不意味着组件只可用于一个单页面，而是<em>每个页面</em>只使用一次。这些组件永远不接受任何 prop，因为它们是为你的应用定制的，而不是它们在你的应用中的上下文。如果你发现有必要添加 prop，那就表明这实际上是一个可复用的组件，<em>只是目前</em>在每个页面里只使用一次。</p>
<div class="style-example example-bad">
<h4 id="反例-10"><a href="#反例-10" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs undefined">components/
|- Heading.vue
|- MySidebar.vue</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-10"><a href="#好例子-10" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- TheHeading.vue
|- TheSidebar.vue</code></pre>
</div>
<h3 id="紧密耦合的组件名强烈推荐"><a href="#紧密耦合的组件名强烈推荐" class="headerlink" title="紧密耦合的组件名强烈推荐"></a>紧密耦合的组件名<sup data-p="b">强烈推荐</sup></h3><p><strong>和父组件紧密耦合的子组件应该以父组件名作为前缀命名。</strong></p>
<p>如果一个组件只在某个父组件的场景下有意义，这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件，所以这样做可以把相关联的文件排在一起。</p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>你可以试着通过在其父组件命名的目录中嵌套子组件以解决这个问题。比如：</p>
<pre><code class="hljs undefined">components/
|- TodoList/
   |- Item/
      |- index.vue
      |- Button.vue
   |- index.vue</code></pre>
<p>或：</p>
<pre><code class="hljs undefined">components/
|- TodoList/
   |- Item/
      |- Button.vue
   |- Item.vue
|- TodoList.vue</code></pre>
<p>但是这种方式并不推荐，因为这会导致：</p>
<ul>
<li>许多文件的名字相同，使得在编辑器中快速切换文件变得困难。</li>
<li>过多嵌套的子目录增加了在编辑器侧边栏中浏览组件所花的时间。</li>
</ul>
</details>
<div class="style-example example-bad">
<h4 id="反例-11"><a href="#反例-11" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs undefined">components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue</code></pre>
<pre><code class="hljs undefined">components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-11"><a href="#好例子-11" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue</code></pre>
<pre><code class="hljs undefined">components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue</code></pre>
</div>
<h3 id="组件名中的单词顺序强烈推荐"><a href="#组件名中的单词顺序强烈推荐" class="headerlink" title="组件名中的单词顺序强烈推荐"></a>组件名中的单词顺序<sup data-p="b">强烈推荐</sup></h3><p><strong>组件名应该以高级别的 (通常是一般化描述的) 单词开头，以描述性的修饰词结尾。</strong></p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>你可能会疑惑：</p>
<blockquote>
<p>“为什么我们给组件命名时不多遵从自然语言呢？”</p>
</blockquote>
<p>在自然的英文里，形容词和其它描述语通常都出现在名词之前，否则需要使用连接词。比如：</p>
<ul>
<li>Coffee <em>with</em> milk</li>
<li>Soup <em>of the</em> day</li>
<li>Visitor <em>to the</em> museum</li>
</ul>
<p>如果你愿意，你完全可以在组件名里包含这些连接词，但是单词的顺序很重要。</p>
<p>同样要注意<strong>在你的应用中所谓的“高级别”是跟语境有关的</strong>。比如对于一个带搜索表单的应用来说，它可能包含这样的组件：</p>
<pre><code class="hljs undefined">components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue</code></pre>
<p>你可能注意到了，我们很难看出来哪些组件是针对搜索的。现在我们来根据规则给组件重新命名：</p>
<pre><code class="hljs undefined">components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputExcludeGlob.vue
|- SearchInputQuery.vue
|- SettingsCheckboxLaunchOnStartup.vue
|- SettingsCheckboxTerms.vue</code></pre>
<p>因为编辑器通常会按字母顺序组织文件，所以现在组件之间的重要关系一目了然。</p>
<p>你可能想换成多级目录的方式，把所有的搜索组件放到“search”目录，把所有的设置组件放到“settings”目录。我们只推荐在非常大型 (如有 100+ 个组件) 的应用下才考虑这么做，因为：</p>
<ul>
<li>在多级目录间找来找去，要比在单个 <code>components</code> 目录下滚动查找要花费更多的精力。</li>
<li>存在组件重名 (比如存在多个 <code>ButtonDelete</code> 组件) 的时候在编辑器里更难快速定位。</li>
<li>让重构变得更难，因为为一个移动了的组件更新相关引用时，查找/替换通常并不高效。</li>
</ul>
</details>
<div class="style-example example-bad">
<h4 id="反例-12"><a href="#反例-12" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs undefined">components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-12"><a href="#好例子-12" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue</code></pre>
</div>
<h3 id="自闭合组件强烈推荐"><a href="#自闭合组件强烈推荐" class="headerlink" title="自闭合组件强烈推荐"></a>自闭合组件<sup data-p="b">强烈推荐</sup></h3><p><strong>在<a href="../guide/single-file-components.html">单文件组件</a>、字符串模板和 <a href="../guide/render-function.html#JSX">JSX</a> 中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样做。</strong></p>
<p>自闭合组件表示它们不仅没有内容，而且<strong>刻意</strong>没有内容。其不同之处就好像书上的一页白纸对比贴有“本页有意留白”标签的白纸。而且没有了额外的闭合标签，你的代码也更简洁。</p>
<p>不幸的是，HTML 并不支持自闭合的自定义元素——只有<a href="https://www.w3.org/TR/html/syntax.html#void-elements" target="_blank" rel="noopener">官方的“空”元素</a>。所以上述策略仅适用于进入 DOM 之前 Vue 的模板编译器能够触达的地方，然后再产出符合 DOM 规范的 HTML。</p>
<div class="style-example example-bad">
<h4 id="反例-13"><a href="#反例-13" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在单文件组件、字符串模板和 JSX 中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">MyComponent</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在 DOM 模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>/&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-13"><a href="#好例子-13" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在单文件组件、字符串模板和 JSX 中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span>/&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在 DOM 模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span></code></pre>
</div>
<h3 id="模板中的组件名大小写强烈推荐"><a href="#模板中的组件名大小写强烈推荐" class="headerlink" title="模板中的组件名大小写强烈推荐"></a>模板中的组件名大小写<sup data-p="b">强烈推荐</sup></h3><p><strong>对于绝大多数项目来说，在<a href="../guide/single-file-components.html">单文件组件</a>和字符串模板中组件名应该总是 PascalCase 的——但是在 DOM 模板中总是 kebab-case 的。</strong></p>
<p>PascalCase 相比 kebab-case 有一些优势：</p>
<ul>
<li>编辑器可以在模板里自动补全组件名，因为 PascalCase 同样适用于 JavaScript。</li>
<li><code>&lt;MyComponent&gt;</code> 视觉上比 <code>&lt;my-component&gt;</code> 更能够和单个单词的 HTML 元素区别开来，因为前者的不同之处有两个大写字母，后者只有一个横线。</li>
<li>如果你在模板中使用任何非 Vue 的自定义元素，比如一个 Web Component，PascalCase 确保了你的 Vue 组件在视觉上仍然是易识别的。</li>
</ul>
<p>不幸的是，由于 HTML 是大小写不敏感的，在 DOM 模板中必须仍使用 kebab-case。</p>
<p>还请注意，如果你已经是 kebab-case 的重度用户，那么与 HTML 保持一致的命名约定且在多个项目中保持相同的大小写规则就可能比上述优势更为重要了。在这些情况下，<strong>在所有的地方都使用 kebab-case 同样是可以接受的。</strong></p>
<div class="style-example example-bad">
<h4 id="反例-14"><a href="#反例-14" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在单文件组件和字符串模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mycomponent</span>/&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在单文件组件和字符串模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">myComponent</span>/&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在 DOM 模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">MyComponent</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-14"><a href="#好例子-14" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在单文件组件和字符串模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span>/&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在 DOM 模板中 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span></code></pre>
<p>或者</p>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在所有地方 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span></code></pre>
</div>
<h3 id="JS-JSX-中的组件名大小写强烈推荐"><a href="#JS-JSX-中的组件名大小写强烈推荐" class="headerlink" title="JS/JSX 中的组件名大小写强烈推荐"></a>JS/JSX 中的组件名大小写<sup data-p="b">强烈推荐</sup></h3><p><strong>JS/<a href="../guide/render-function.html#JSX">JSX</a> 中的组件名应该始终是 PascalCase 的，尽管在较为简单的应用中只使用 <code>Vue.component</code> 进行全局组件注册时，可以使用 kebab-case 字符串。</strong></p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>在 JavaScript 中，PascalCase 是类和构造函数 (本质上任何可以产生多份不同实例的东西) 的命名约定。Vue 组件也有多份实例，所以同样使用 PascalCase 是有意义的。额外的好处是，在 JSX (和模板) 里使用 PascalCase 使得代码的读者更容易分辨 Vue 组件和 HTML 元素。</p>
<p>然而，对于<strong>只</strong>通过 <code>Vue.component</code> 定义全局组件的应用来说，我们推荐 kebab-case 作为替代。原因是：</p>
<ul>
<li>全局组件很少被 JavaScript 引用，所以遵守 JavaScript 的命名约定意义不大。</li>
<li>这些应用往往包含许多 DOM 内的模板，这种情况下是<a href="#模板中的组件名大小写-强烈推荐"><strong>必须</strong>使用 kebab-case</a> 的。</li>
</ul>
</details>
<div class="style-example example-bad">
<h4 id="反例-15"><a href="#反例-15" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'myComponent'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">import</span> myComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./MyComponent.vue'</span></code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">name</span>: <span class="hljs-string">'myComponent'</span>,
  <span class="hljs-comment">// ...</span>
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">name</span>: <span class="hljs-string">'my-component'</span>,
  <span class="hljs-comment">// ...</span>
&#125;</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-15"><a href="#好例子-15" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'MyComponent'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)</code></pre>
<pre><code class="hljs js">Vue.component(<span class="hljs-string">'my-component'</span>, &#123;
  <span class="hljs-comment">// ...</span>
&#125;)</code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">import</span> MyComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./MyComponent.vue'</span></code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">name</span>: <span class="hljs-string">'MyComponent'</span>,
  <span class="hljs-comment">// ...</span>
&#125;</code></pre>
</div>
<h3 id="完整单词的组件名强烈推荐"><a href="#完整单词的组件名强烈推荐" class="headerlink" title="完整单词的组件名强烈推荐"></a>完整单词的组件名<sup data-p="b">强烈推荐</sup></h3><p><strong>组件名应该倾向于完整单词而不是缩写。</strong></p>
<p>编辑器中的自动补全已经让书写长命名的代价非常之低了，而其带来的明确性却是非常宝贵的。不常用的缩写尤其应该避免。</p>
<div class="style-example example-bad">
<h4 id="反例-16"><a href="#反例-16" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs undefined">components/
|- SdSettings.vue
|- UProfOpts.vue</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-16"><a href="#好例子-16" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs undefined">components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue</code></pre>
</div>
<h3 id="Prop-名大小写强烈推荐"><a href="#Prop-名大小写强烈推荐" class="headerlink" title="Prop 名大小写强烈推荐"></a>Prop 名大小写<sup data-p="b">强烈推荐</sup></h3><p><strong>在声明 prop 的时候，其命名应该始终使用 camelCase，而在模板和 <a href="../guide/render-function.html#JSX">JSX</a> 中应该始终使用 kebab-case。</strong></p>
<p>我们单纯的遵循每个语言的约定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中则是 kebab-case。</p>
<div class="style-example example-bad">
<h4 id="反例-17"><a href="#反例-17" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">props: &#123;
  <span class="hljs-string">'greeting-text'</span>: <span class="hljs-built_in">String</span>
&#125;</code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">WelcomeMessage</span> <span class="hljs-attr">greetingText</span>=<span class="hljs-string">"hi"</span>/&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-17"><a href="#好例子-17" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">props: &#123;
  <span class="hljs-attr">greetingText</span>: <span class="hljs-built_in">String</span>
&#125;</code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">WelcomeMessage</span> <span class="hljs-attr">greeting-text</span>=<span class="hljs-string">"hi"</span>/&gt;</span></code></pre>
</div>
<h3 id="多个-attribute-的元素强烈推荐"><a href="#多个-attribute-的元素强烈推荐" class="headerlink" title="多个 attribute 的元素强烈推荐"></a>多个 attribute 的元素<sup data-p="b">强烈推荐</sup></h3><p><strong>多个 attribute 的元素应该分多行撰写，每个 attribute 一行。</strong></p>
<p>在 JavaScript 中，用多行分隔对象的多个 property 是很常见的最佳实践，因为这样更易读。模板和 <a href="../guide/render-function.html#JSX">JSX</a> 值得我们做相同的考虑。</p>
<div class="style-example example-bad">
<h4 id="反例-18"><a href="#反例-18" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://vuejs.org/images/logo.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Vue Logo"</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span> <span class="hljs-attr">foo</span>=<span class="hljs-string">"a"</span> <span class="hljs-attr">bar</span>=<span class="hljs-string">"b"</span> <span class="hljs-attr">baz</span>=<span class="hljs-string">"c"</span>/&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-18"><a href="#好例子-18" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
  <span class="hljs-attr">src</span>=<span class="hljs-string">"https://vuejs.org/images/logo.png"</span>
  <span class="hljs-attr">alt</span>=<span class="hljs-string">"Vue Logo"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span>
  <span class="hljs-attr">foo</span>=<span class="hljs-string">"a"</span>
  <span class="hljs-attr">bar</span>=<span class="hljs-string">"b"</span>
  <span class="hljs-attr">baz</span>=<span class="hljs-string">"c"</span>
/&gt;</span></code></pre>
</div>
<h3 id="模板中简单的表达式强烈推荐"><a href="#模板中简单的表达式强烈推荐" class="headerlink" title="模板中简单的表达式强烈推荐"></a>模板中简单的表达式<sup data-p="b">强烈推荐</sup></h3><p><strong>组件模板应该只包含简单的表达式，复杂的表达式则应该重构为计算属性或方法。</strong></p>
<p>复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的<em>是什么</em>，而非<em>如何</em>计算那个值。而且计算属性和方法使得代码可以重用。</p>
<div class="style-example example-bad">
<h4 id="反例-19"><a href="#反例-19" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html">&#123;&#123;
  fullName.split(' ').map(function (word) &#123;
    return word[0].toUpperCase() + word.slice(1)
  &#125;).join(' ')
&#125;&#125;</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-19"><a href="#好例子-19" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- 在模板中 --&gt;</span>
&#123;&#123; normalizedFullName &#125;&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// 复杂表达式已经移入一个计算属性</span>
<span class="hljs-attr">computed</span>: &#123;
  <span class="hljs-attr">normalizedFullName</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.fullName.split(<span class="hljs-string">' '</span>).map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">word</span>) </span>&#123;
      <span class="hljs-keyword">return</span> word[<span class="hljs-number">0</span>].toUpperCase() + word.slice(<span class="hljs-number">1</span>)
    &#125;).join(<span class="hljs-string">' '</span>)
  &#125;
&#125;</code></pre>
</div>
<h3 id="简单的计算属性强烈推荐"><a href="#简单的计算属性强烈推荐" class="headerlink" title="简单的计算属性强烈推荐"></a>简单的计算属性<sup data-p="b">强烈推荐</sup></h3><p><strong>应该把复杂计算属性分割为尽可能多的更简单的 property。</strong></p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>更简单、命名得当的计算属性是这样的：</p>
<ul>
<li><p><strong>易于测试</strong></p>
<p>当每个计算属性都包含一个非常简单且很少依赖的表达式时，撰写测试以确保其正确工作就会更加容易。</p>
</li>
<li><p><strong>易于阅读</strong></p>
<p>简化计算属性要求你为每一个值都起一个描述性的名称，即便它不可复用。这使得其他开发者 (以及未来的你) 更容易专注在他们关心的代码上并搞清楚发生了什么。</p>
</li>
<li><p><strong>更好的“拥抱变化”</strong></p>
<p>任何能够命名的值都可能用在视图上。举个例子，我们可能打算展示一个信息，告诉用户他们存了多少钱；也可能打算计算税费，但是可能会分开展现，而不是作为总价的一部分。</p>
<p>小的、专注的计算属性减少了信息使用时的假设性限制，所以需求变更时也用不着那么多重构了。</p>
</li>
</ul>
</details>
<div class="style-example example-bad">
<h4 id="反例-20"><a href="#反例-20" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">computed: &#123;
  <span class="hljs-attr">price</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">var</span> basePrice = <span class="hljs-keyword">this</span>.manufactureCost / (<span class="hljs-number">1</span> - <span class="hljs-keyword">this</span>.profitMargin)
    <span class="hljs-keyword">return</span> (
      basePrice -
      basePrice * (<span class="hljs-keyword">this</span>.discountPercent || <span class="hljs-number">0</span>)
    )
  &#125;
&#125;</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-20"><a href="#好例子-20" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">computed: &#123;
  <span class="hljs-attr">basePrice</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.manufactureCost / (<span class="hljs-number">1</span> - <span class="hljs-keyword">this</span>.profitMargin)
  &#125;,
  <span class="hljs-attr">discount</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.basePrice * (<span class="hljs-keyword">this</span>.discountPercent || <span class="hljs-number">0</span>)
  &#125;,
  <span class="hljs-attr">finalPrice</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.basePrice - <span class="hljs-keyword">this</span>.discount
  &#125;
&#125;</code></pre>
</div>
<h3 id="带引号的-attribute-值强烈推荐"><a href="#带引号的-attribute-值强烈推荐" class="headerlink" title="带引号的 attribute 值强烈推荐"></a>带引号的 attribute 值<sup data-p="b">强烈推荐</sup></h3><p><strong>非空 HTML attribute 值应该始终带引号 (单引号或双引号，以 JS 中未使用的为准)。</strong></p>
<p>在 HTML 中不带空格的 attribute 值是可以没有引号的，但这鼓励了大家在特征值里<em>不写</em>空格，导致可读性变差。</p>
<div class="style-example example-bad">
<h4 id="反例-21"><a href="#反例-21" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">text</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">AppSidebar</span> <span class="hljs-attr">:style</span>=<span class="hljs-string">&#123;width:sidebarWidth+</span>'<span class="hljs-attr">px</span>'&#125;&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-21"><a href="#好例子-21" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">AppSidebar</span> <span class="hljs-attr">:style</span>=<span class="hljs-string">"&#123; width: sidebarWidth + 'px' &#125;"</span>&gt;</span></code></pre>
</div>
<h3 id="指令缩写强烈推荐"><a href="#指令缩写强烈推荐" class="headerlink" title="指令缩写强烈推荐"></a>指令缩写<sup data-p="b">强烈推荐</sup></h3><p><strong>指令缩写 (用 <code>:</code> 表示 <code>v-bind:</code>、用 <code>@</code> 表示 <code>v-on:</code> 和用 <code>#</code> 表示 <code>v-slot:</code>) 应该要么都用要么都不用。</strong></p>
<div class="style-example example-bad">
<h4 id="反例-22"><a href="#反例-22" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">v-bind:value</span>=<span class="hljs-string">"newTodoText"</span>
  <span class="hljs-attr">:placeholder</span>=<span class="hljs-string">"newTodoInstructions"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">v-on:input</span>=<span class="hljs-string">"onInput"</span>
  @<span class="hljs-attr">focus</span>=<span class="hljs-string">"onFocus"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-slot:header</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Here might be a page title<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">template</span> #<span class="hljs-attr">footer</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here's some contact info<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-22"><a href="#好例子-22" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">:value</span>=<span class="hljs-string">"newTodoText"</span>
  <span class="hljs-attr">:placeholder</span>=<span class="hljs-string">"newTodoInstructions"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">v-bind:value</span>=<span class="hljs-string">"newTodoText"</span>
  <span class="hljs-attr">v-bind:placeholder</span>=<span class="hljs-string">"newTodoInstructions"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  @<span class="hljs-attr">input</span>=<span class="hljs-string">"onInput"</span>
  @<span class="hljs-attr">focus</span>=<span class="hljs-string">"onFocus"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">v-on:input</span>=<span class="hljs-string">"onInput"</span>
  <span class="hljs-attr">v-on:focus</span>=<span class="hljs-string">"onFocus"</span>
&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-slot:header</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Here might be a page title<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-slot:footer</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here's some contact info<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span> #<span class="hljs-attr">header</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Here might be a page title<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">template</span> #<span class="hljs-attr">footer</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here's some contact info<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></code></pre>
</div>
<h2 id="优先级-C-的规则：推荐-将选择和认知成本最小化"><a href="#优先级-C-的规则：推荐-将选择和认知成本最小化" class="headerlink" title="优先级 C 的规则：推荐 (将选择和认知成本最小化)"></a>优先级 C 的规则：推荐 (将选择和认知成本最小化)</h2><h3 id="组件-实例的选项的顺序推荐"><a href="#组件-实例的选项的顺序推荐" class="headerlink" title="组件/实例的选项的顺序推荐"></a>组件/实例的选项的顺序<sup data-p="c">推荐</sup></h3><p><strong>组件/实例的选项应该有统一的顺序。</strong></p>
<p>这是我们推荐的组件选项默认顺序。它们被划分为几大类，所以你也能知道从插件里添加的新 property 应该放到哪里。</p>
<ol>
<li><p><strong>副作用</strong> (触发组件外的影响)</p>
<ul>
<li><code>el</code></li>
</ul>
</li>
<li><p><strong>全局感知</strong> (要求组件以外的知识)</p>
<ul>
<li><code>name</code></li>
<li><code>parent</code></li>
</ul>
</li>
<li><p><strong>组件类型</strong> (更改组件的类型)</p>
<ul>
<li><code>functional</code></li>
</ul>
</li>
<li><p><strong>模板修改器</strong> (改变模板的编译方式)</p>
<ul>
<li><code>delimiters</code></li>
<li><code>comments</code></li>
</ul>
</li>
<li><p><strong>模板依赖</strong> (模板内使用的资源)</p>
<ul>
<li><code>components</code></li>
<li><code>directives</code></li>
<li><code>filters</code></li>
</ul>
</li>
<li><p><strong>组合</strong> (向选项里合并 property)</p>
<ul>
<li><code>extends</code></li>
<li><code>mixins</code></li>
</ul>
</li>
<li><p><strong>接口</strong> (组件的接口)</p>
<ul>
<li><code>inheritAttrs</code></li>
<li><code>model</code></li>
<li><code>props</code>/<code>propsData</code></li>
</ul>
</li>
<li><p><strong>本地状态</strong> (本地的响应式 property)</p>
<ul>
<li><code>data</code></li>
<li><code>computed</code></li>
</ul>
</li>
<li><p><strong>事件</strong> (通过响应式事件触发的回调)</p>
<ul>
<li><code>watch</code></li>
<li>生命周期钩子 (按照它们被调用的顺序)<ul>
<li><code>beforeCreate</code></li>
<li><code>created</code></li>
<li><code>beforeMount</code></li>
<li><code>mounted</code></li>
<li><code>beforeUpdate</code></li>
<li><code>updated</code></li>
<li><code>activated</code></li>
<li><code>deactivated</code></li>
<li><code>beforeDestroy</code></li>
<li><code>destroyed</code></li>
</ul>
</li>
</ul>
</li>
<li><p><strong>非响应式的 property</strong> (不依赖响应系统的实例 property)</p>
<ul>
<li><code>methods</code></li>
</ul>
</li>
<li><p><strong>渲染</strong> (组件输出的声明式描述)</p>
<ul>
<li><code>template</code>/<code>render</code></li>
<li><code>renderError</code></li>
</ul>
</li>
</ol>
<h3 id="元素-attribute-的顺序推荐"><a href="#元素-attribute-的顺序推荐" class="headerlink" title="元素 attribute 的顺序推荐"></a>元素 attribute 的顺序<sup data-p="c">推荐</sup></h3><p><strong>元素 (包括组件) 的 attribute 应该有统一的顺序。</strong></p>
<p>这是我们为组件选项推荐的默认顺序。它们被划分为几大类，所以你也能知道新添加的自定义 attribute 和指令应该放到哪里。</p>
<ol>
<li><p><strong>定义</strong> (提供组件的选项)</p>
<ul>
<li><code>is</code></li>
</ul>
</li>
<li><p><strong>列表渲染</strong> (创建多个变化的相同元素)</p>
<ul>
<li><code>v-for</code></li>
</ul>
</li>
<li><p><strong>条件渲染</strong> (元素是否渲染/显示)</p>
<ul>
<li><code>v-if</code></li>
<li><code>v-else-if</code></li>
<li><code>v-else</code></li>
<li><code>v-show</code></li>
<li><code>v-cloak</code></li>
</ul>
</li>
<li><p><strong>渲染方式</strong> (改变元素的渲染方式)</p>
<ul>
<li><code>v-pre</code></li>
<li><code>v-once</code></li>
</ul>
</li>
<li><p><strong>全局感知</strong> (需要超越组件的知识)</p>
<ul>
<li><code>id</code></li>
</ul>
</li>
<li><p><strong>唯一的 attribute</strong> (需要唯一值的 attribute)</p>
<ul>
<li><code>ref</code></li>
<li><code>key</code></li>
</ul>
</li>
<li><p><strong>双向绑定</strong> (把绑定和事件结合起来)</p>
<ul>
<li><code>v-model</code></li>
</ul>
</li>
<li><p><strong>其它 attribute</strong> (所有普通的绑定或未绑定的 attribute)</p>
</li>
<li><p><strong>事件</strong> (组件事件监听器)</p>
<ul>
<li><code>v-on</code></li>
</ul>
</li>
<li><p><strong>内容</strong> (覆写元素的内容)</p>
<ul>
<li><code>v-html</code></li>
<li><code>v-text</code></li>
</ul>
</li>
</ol>
<h3 id="组件-实例选项中的空行推荐"><a href="#组件-实例选项中的空行推荐" class="headerlink" title="组件/实例选项中的空行推荐"></a>组件/实例选项中的空行<sup data-p="c">推荐</sup></h3><p><strong>你可能想在多个 property 之间增加一个空行，特别是在这些选项一屏放不下，需要滚动才能都看到的时候。</strong></p>
<p>当你的组件开始觉得密集或难以阅读时，在多个 property 之间添加空行可以让其变得容易。在一些诸如 Vim 的编辑器里，这样格式化后的选项还能通过键盘被快速导航。</p>
<div class="style-example example-good">
<h4 id="好例子-23"><a href="#好例子-23" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">props: &#123;
  <span class="hljs-attr">value</span>: &#123;
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
  &#125;,

  <span class="hljs-attr">focused</span>: &#123;
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>
  &#125;,

  <span class="hljs-attr">label</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">icon</span>: <span class="hljs-built_in">String</span>
&#125;,

<span class="hljs-attr">computed</span>: &#123;
  <span class="hljs-attr">formattedValue</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-comment">// ...</span>
  &#125;,

  <span class="hljs-attr">inputClasses</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-comment">// ...</span>
  &#125;
&#125;</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// 没有空行在组件易于阅读和导航时也没问题。</span>
<span class="hljs-attr">props</span>: &#123;
  <span class="hljs-attr">value</span>: &#123;
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
  &#125;,
  <span class="hljs-attr">focused</span>: &#123;
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>
  &#125;,
  <span class="hljs-attr">label</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">icon</span>: <span class="hljs-built_in">String</span>
&#125;,
<span class="hljs-attr">computed</span>: &#123;
  <span class="hljs-attr">formattedValue</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-comment">// ...</span>
  &#125;,
  <span class="hljs-attr">inputClasses</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-comment">// ...</span>
  &#125;
&#125;</code></pre>
</div>
<h3 id="单文件组件的顶级元素的顺序推荐"><a href="#单文件组件的顶级元素的顺序推荐" class="headerlink" title="单文件组件的顶级元素的顺序推荐"></a>单文件组件的顶级元素的顺序<sup data-p="c">推荐</sup></h3><p><strong><a href="../guide/single-file-components.html">单文件组件</a>应该总是让 <code>&lt;script&gt;</code>、<code>&lt;template&gt;</code> 和 <code>&lt;style&gt;</code> 标签的顺序保持一致。且 <code>&lt;style&gt;</code> 要放在最后，因为另外两个标签至少要有一个。</strong></p>
<div class="style-example example-bad">
<h4 id="反例-23"><a href="#反例-23" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- ComponentA.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ComponentB.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-24"><a href="#好例子-24" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- ComponentA.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ComponentB.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- ComponentA.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ComponentB.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"><span class="hljs-comment">/* ... */</span></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
</div>
<h2 id="优先级-D-的规则：谨慎使用-有潜在危险的模式"><a href="#优先级-D-的规则：谨慎使用-有潜在危险的模式" class="headerlink" title="优先级 D 的规则：谨慎使用 (有潜在危险的模式)"></a>优先级 D 的规则：谨慎使用 (有潜在危险的模式)</h2><h3 id="没有在-v-if-v-else-if-v-else-中使用-key-谨慎使用"><a href="#没有在-v-if-v-else-if-v-else-中使用-key-谨慎使用" class="headerlink" title="没有在 v-if/v-else-if/v-else 中使用 key 谨慎使用"></a>没有在 <code>v-if</code>/<code>v-else-if</code>/<code>v-else</code> 中使用 <code>key</code> <sup data-p="d">谨慎使用</sup></h3><p><strong>如果一组 <code>v-if</code> + <code>v-else</code> 的元素类型相同，最好使用 <code>key</code> (比如两个 <code>&lt;div&gt;</code> 元素)。</strong></p>
<p>默认情况下，Vue 会尽可能高效的更新 DOM。这意味着其在相同类型的元素之间切换时，会修补已存在的元素，而不是将旧的元素移除然后在同一位置添加一个新元素。如果本不相同的元素被识别为相同，则会出现<a href="https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-priority-d-rules-unintended-consequences" target="_blank" rel="noopener">意料之外的结果</a>。</p>
<div class="style-example example-bad">
<h4 id="反例-24"><a href="#反例-24" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error"</span>&gt;</span>
  错误：&#123;&#123; error &#125;&#125;
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
  &#123;&#123; results &#125;&#125;
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-25"><a href="#好例子-25" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error"</span>
  <span class="hljs-attr">key</span>=<span class="hljs-string">"search-status"</span>
&gt;</span>
  错误：&#123;&#123; error &#125;&#125;
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">v-else</span>
  <span class="hljs-attr">key</span>=<span class="hljs-string">"search-results"</span>
&gt;</span>
  &#123;&#123; results &#125;&#125;
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
</div>
<h3 id="scoped-中的元素选择器谨慎使用"><a href="#scoped-中的元素选择器谨慎使用" class="headerlink" title="scoped 中的元素选择器谨慎使用"></a><code>scoped</code> 中的元素选择器<sup data-p="d">谨慎使用</sup></h3><p><strong>元素选择器应该避免在 <code>scoped</code> 中出现。</strong></p>
<p>在 <code>scoped</code> 样式中，类选择器比元素选择器更好，因为大量使用元素选择器是很慢的。</p>

<details>
<summary>
  <h4>详解</h4>
</summary>

<p>为了给样式设置作用域，Vue 会为元素添加一个独一无二的 attribute，例如 <code>data-v-f3f3eg9</code>。然后修改选择器，使得在匹配选择器的元素中，只有带这个 attribute 才会真正生效 (比如 <code>button[data-v-f3f3eg9]</code>)。</p>
<p>问题在于大量的<a href="http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&amp;sel=a%5Bhref%5D&amp;body=background%3A+%23CFD&amp;ne=1000" target="_blank" rel="noopener">元素和 attribute 组合的选择器</a> (比如 <code>button[data-v-f3f3eg9]</code>) 会比<a href="http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&amp;sel=.class%5Bhref%5D&amp;body=background%3A+%23CFD&amp;ne=1000" target="_blank" rel="noopener">类和 attribute 组合的选择器</a>慢，所以应该尽可能选用类选择器。</p>
</details>
<div class="style-example example-bad">
<h4 id="反例-25"><a href="#反例-25" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>X<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-tag">button</span> &#123;
  <span class="hljs-attribute">background-color</span>: red;
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-26"><a href="#好例子-26" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-close"</span>&gt;</span>X<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.btn-close</span> &#123;
  <span class="hljs-attribute">background-color</span>: red;
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre>
</div>
<h3 id="隐性的父子组件通信谨慎使用"><a href="#隐性的父子组件通信谨慎使用" class="headerlink" title="隐性的父子组件通信谨慎使用"></a>隐性的父子组件通信<sup data-p="d">谨慎使用</sup></h3><p><strong>应该优先通过 prop 和事件进行父子组件之间的通信，而不是 <code>this.$parent</code> 或变更 prop。</strong></p>
<p>一个理想的 Vue 应用是 prop 向下传递，事件向上传递的。遵循这一约定会让你的组件更易于理解。然而，在一些边界情况下 prop 的变更或 <code>this.$parent</code> 能够简化两个深度耦合的组件。</p>
<p>问题在于，这种做法在很多<em>简单</em>的场景下可能会更方便。但请当心，不要为了一时方便 (少写代码) 而牺牲数据流向的简洁性 (易于理解)。</p>
<div class="style-example example-bad">
<h4 id="反例-26"><a href="#反例-26" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'TodoItem'</span>, &#123;
  <span class="hljs-attr">props</span>: &#123;
    <span class="hljs-attr">todo</span>: &#123;
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    &#125;
  &#125;,
  <span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;input v-model="todo.text"&gt;'</span>
&#125;)</code></pre>
<pre><code class="hljs js">Vue.component(<span class="hljs-string">'TodoItem'</span>, &#123;
  <span class="hljs-attr">props</span>: &#123;
    <span class="hljs-attr">todo</span>: &#123;
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    &#125;
  &#125;,
  <span class="hljs-attr">methods</span>: &#123;
    removeTodo () &#123;
      <span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">this</span>
      vm.$parent.todos = vm.$parent.todos.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">todo</span>) </span>&#123;
        <span class="hljs-keyword">return</span> todo.id !== vm.todo.id
      &#125;)
    &#125;
  &#125;,
  <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;span&gt;
      &#123;&#123; todo.text &#125;&#125;
      &lt;button @click="removeTodo"&gt;
        X
      &lt;/button&gt;
    &lt;/span&gt;
  `</span>
&#125;)</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-27"><a href="#好例子-27" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js">Vue.component(<span class="hljs-string">'TodoItem'</span>, &#123;
  <span class="hljs-attr">props</span>: &#123;
    <span class="hljs-attr">todo</span>: &#123;
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    &#125;
  &#125;,
  <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;input
      :value="todo.text"
      @input="$emit('input', $event.target.value)"
    &gt;
  `</span>
&#125;)</code></pre>
<pre><code class="hljs js">Vue.component(<span class="hljs-string">'TodoItem'</span>, &#123;
  <span class="hljs-attr">props</span>: &#123;
    <span class="hljs-attr">todo</span>: &#123;
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    &#125;
  &#125;,
  <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;span&gt;
      &#123;&#123; todo.text &#125;&#125;
      &lt;button @click="$emit('delete')"&gt;
        X
      &lt;/button&gt;
    &lt;/span&gt;
  `</span>
&#125;)</code></pre>
</div>
<h3 id="非-Flux-的全局状态管理谨慎使用"><a href="#非-Flux-的全局状态管理谨慎使用" class="headerlink" title="非 Flux 的全局状态管理谨慎使用"></a>非 Flux 的全局状态管理<sup data-p="d">谨慎使用</sup></h3><p><strong>应该优先通过 <a href="https://github.com/vuejs/vuex" target="_blank" rel="noopener">Vuex</a> 管理全局状态，而不是通过 <code>this.$root</code> 或一个全局事件总线。</strong></p>
<p>通过 <code>this.$root</code> 和/或<a href="../guide/migration.html#dispatch-和-broadcast-替换">全局事件总线</a>管理状态在很多简单的情况下都是很方便的，但是并不适用于绝大多数的应用。</p>
<p>Vuex 是 Vue 的<a href="../guide/state-management.html#类-Flux-状态管理的官方实现">官方类 flux 实现</a>，其提供的不仅是一个管理状态的中心区域，还是组织、追踪和调试状态变更的好工具。它很好地集成在了 Vue 生态系统之中 (包括完整的 <a href="../guide/installation.html#Vue-Devtools">Vue DevTools</a> 支持)。</p>

<div class="style-example example-bad">
<h4 id="反例-27"><a href="#反例-27" class="headerlink" title="反例"></a>反例</h4><pre><code class="hljs js"><span class="hljs-comment">// main.js</span>
<span class="hljs-keyword">new</span> Vue(&#123;
  <span class="hljs-attr">data</span>: &#123;
    <span class="hljs-attr">todos</span>: []
  &#125;,
  <span class="hljs-attr">created</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">this</span>.$on(<span class="hljs-string">'remove-todo'</span>, <span class="hljs-keyword">this</span>.removeTodo)
  &#125;,
  <span class="hljs-attr">methods</span>: &#123;
    <span class="hljs-attr">removeTodo</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">todo</span>) </span>&#123;
      <span class="hljs-keyword">var</span> todoIdToRemove = todo.id
      <span class="hljs-keyword">this</span>.todos = <span class="hljs-keyword">this</span>.todos.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">todo</span>) </span>&#123;
        <span class="hljs-keyword">return</span> todo.id !== todoIdToRemove
      &#125;)
    &#125;
  &#125;
&#125;)</code></pre>
</div>
<div class="style-example example-good">
<h4 id="好例子-28"><a href="#好例子-28" class="headerlink" title="好例子"></a>好例子</h4><pre><code class="hljs js"><span class="hljs-comment">// store/modules/todos.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">state</span>: &#123;
    <span class="hljs-attr">list</span>: []
  &#125;,
  <span class="hljs-attr">mutations</span>: &#123;
    REMOVE_TODO (state, todoId) &#123;
      state.list = state.list.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.id !== todoId)
    &#125;
  &#125;,
  <span class="hljs-attr">actions</span>: &#123;
    removeTodo (&#123; commit, state &#125;, todo) &#123;
      commit(<span class="hljs-string">'REMOVE_TODO'</span>, todo.id)
    &#125;
  &#125;
&#125;</code></pre>
<pre><code class="hljs html"><span class="hljs-comment">&lt;!-- TodoItem.vue --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
    &#123;&#123; todo.text &#125;&#125;
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"removeTodo(todo)"</span>&gt;</span>
      X
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> &#123; mapActions &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">props</span>: &#123;
    <span class="hljs-attr">todo</span>: &#123;
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    &#125;
  &#125;,
  <span class="hljs-attr">methods</span>: mapActions([<span class="hljs-string">'removeTodo'</span>])
&#125;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
</div>

<script>
(function () {
  var enforcementTypes = {
    none: '<span title="这一规则无法强制执行">自律</span>',
    runtime: '运行时错误',
    linter: '<a href="https://github.com/vuejs/eslint-plugin-vue#eslint-plugin-vue" target="_blank" rel="noopener noreferrer">plugin:vue/recommended</a>'
  }
  Vue.component('sg-enforcement', {
    template: '\
      <span>\
        <strong>强制执行</strong>:\
        <span class="style-rule-tag" v-html="humanType"/>\
      </span>\
    ',
    props: {
      type: {
        type: String,
        required: true,
        validate: function (value) {
          Object.keys(enforcementTypes).indexOf(value) !== -1
        }
      }
    },
    computed: {
      humanType: function () {
        return enforcementTypes[this.type]
      }
    }
  })

  // new Vue({
  //  el: '#main'
  // })
})()
</script>


  
  
  <div class="footer">
      <script src="//m.servedby-buysellads.com/monetization.js" type="text/javascript"></script>
<div id="bsa-native"></div>
<script>
_bsa.init('custom', 'CKYD62QM', 'placement:vuejsorg',
  {
    target: '#bsa-native',
    template: '<a class="native-box" href="##statlink##"><div class="native-sponsor">Sponsor</div><div class="native-text"><strong>##company##</strong> — ##description##</div></a>'
  }
);
</script>


    发现错误？想参与编辑？
    <a href="https://github.com/vuejs/cn.vuejs.org/blob/master/src/v2/style-guide/index.md" rel="noopener" target="_blank">
      在 GitHub 上编辑此页！
    </a>
    <!-- Deployed on
    <a href="https://url.netlify.com/HJ8X2mxP8" rel="noopener" target="_blank">
      Netlify
    </a>. -->
  </div>
</div>

      </div>
      <script src="/vue2/js/smooth-scroll.min.js"></script>
    

    <!-- main custom script for sidebars, version selects etc. -->
    <script src="/vue2/js/css.escape.js"></script>
    <script src="/vue2/js/common.js"></script>

    <!-- search -->
    <link href="//code.bdstatic.com/npm/docsearch.js@1.5.0/dist/cdn/docsearch.min.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="/vue2/css/search.css">
    <script src="//code.bdstatic.com/npm/docsearch.js@1.5.0/dist/cdn/docsearch.min.js"></script>
    <script>
    [
      '#search-query-nav',
      '#search-query-sidebar',
      '#search-query-menu'
    ].forEach(function (selector) {
      if (!document.querySelector(selector)) return
      // search index defaults to v2
      var match = window.location.pathname.match(/^\/(v\d+)/)
      var version = match ? match[1] : 'v2'
      docsearch({
      appId: 'BH4D9OD16A',
      apiKey: '5638280abff9d207417bb03be05f0b25',
      indexName: 'vuejs_cn2',
      inputSelector: selector,
      algoliaOptions: { facetFilters: ["version:" + version] },
      autocompleteOptions: { hint: false, appendTo: 'body'}
      })
    })
    </script>
  </body>
</html>
